/*
/
 /  Arduino 'cassette' engine.
 /
 /  Developed by Charlie Robson in 2008.
 /
 /  This is half of a solution for getting data into an arduino. The other
 /  half being code to generate frequency shift keyed (FSK) data in the form
 /  of WAV files which should be widely playable. These can be recorded or
 /  otherwise electronically distributed. Why do it this way? 1. Because it's
 /  funny. 2. Having given an updatable arduino-powered 'toy' to someone, I
 /  can't expect them to re-program the device by traditional means. Every-
 /  one has a means of playing a sound.
 /
 /
 /  On with the show.
 /
 /  The data is encoded like so:
 /
 /    Some seconds of '0' bits [lead-in]
 /    High byte of data length
 /    Low byte of data length
 /    Data[]
 /
 /  Every byte is represented by 10 bits - a start ['1'] bit, 8 data bits, and
 /  a stop ['0'] bit.
 /
 /  Decoding the data is done something like so:
 /
 /    Await a rising edge then take 2 samples at a period which will allow us
 /    to distinguish a 0 or 1 bit. Sampling 2 identical values yields a 0 bit.
 /    Delay so the next bit read will occur when the signal is in a low period.
 /
 /  Following is a picture of a '0' bit, or low frequency cycle, followed by
 /  a '1' bit or high frequency cycle.
 /
 /    The X shows a rough expected time at which we start the bit reading.
 /    The 0 shows relative time zero, when we detect the rising edge.
 /    The + signs show the times at which we sample.
 /    The * shows the time at which data is yielded. This could be adjusted.
 /
 /        __`_____`__             __
 /       |  `     `  |           |
 /       |  `     `  |           |
 /       |  `     `  |           |
 /     ` |  `     `  |  `        |
 /   __`_|  `     `  | _`________|
 /     ` `  `     `     `
 /     X 0  +     +     *
 /     ` `__`__   `   __`__
 /     ` |  `  |  `  |     |
 /     ` |  `  |  `  |     |
 /       |     |     |     |
 /       |     |     |     |     |
 /   ____|     |_____|     |_____|
 /       `
 /       `
 /       |-----------------------| = usPerCycle        = 1360uS
 /       |-----------|             = usPerHalfCycle    = 680uS
 /       |-----|                   = usPerQuarterCycle = 340uS
 /       |--|                      = usPerEighthCycle  = 170uS
 /
 /
 /
 /  It's assumed that the audio signal is connected to PORTB-0 which is
 /  digital pin 8. If you'd like to change that, then replace occurrences
 /  of:
 /
 /      PINB & 1
 /
 /  with the direct bit-access for your implimentation. I do it this way
 /  because it's slightly faster. You'll also need to change the logic
 /  in readBit as this relies on the fact that we work with bit 0. 
 /
 */

#include "wprogram.h"

// number of samples that represent one '0' cycle at 44.1khz
//
const int f1 = 60;

// time for 1 '0' cycle
//
const int usPerCycle = (int)(((double)f1 / 44100) * 1000000.0);

const int usPerHalfCycle = (int)(((double)f1 / 44100) * 500000.0);
const int usPerQuarterCycle = (int)(((double)f1 / 44100) * 250000.0);
const int usPerEighthCycle = (int)(((double)f1 / 44100) * 125000.0);


// The start bit is the complement of the bit used for the lead-in
// so we can detect data start.
//
const int LEADBIT = 0;
const int STARTBIT = (1-LEADBIT);
const int STOPBIT = (1-STARTBIT);


// Useful for timeout conditions.
//
extern volatile unsigned long timer0_overflow_count;

namespace ace
{
  // Returns true when the lead-in is detected.
  // The timeout, in millis, is the time allowed for the signal to
  // raise its first edge. Used for level setting.
  //
  bool detectLeadIn(unsigned long timeout);


  // Load data. The data arrives in 512-byte chunks, and the buffer transfer
  // function is called when a block has arrived.
  //
  // Returns true if all went well. Return false if there was a problem -
  // returnCode indicates the point of failure.
  //
  // Should only be called when the lead-in is detected.
  //
  bool loadFile(unsigned long timeout, byte* databuffer, void(*bufferTransferFn)(int), int& returnCode);
};
